package com.neo.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class RequestLoggingFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        long startTime = System.currentTimeMillis();
        chain.doFilter(request, response);
        long duration = System.currentTimeMillis() - startTime;

        Map<String, Object> logInfo = new HashMap<>();
        logInfo.put("clientIp", getClientIpAddress(httpRequest));
        logInfo.put("method", httpRequest.getMethod());
        logInfo.put("uri", httpRequest.getRequestURI());
        logInfo.put("queryString", httpRequest.getQueryString());
        logInfo.put("userAgent", httpRequest.getHeader("User-Agent"));
        logInfo.put("referer", httpRequest.getHeader("Referer"));
        logInfo.put("statusCode", httpResponse.getStatus());
        logInfo.put("duration", duration);
        logInfo.put("timestamp", System.currentTimeMillis());
        logInfo.put("protocol", httpRequest.getProtocol());
        logInfo.put("locale", httpRequest.getLocale().toString());
        logInfo.put("contentType", httpRequest.getContentType());
        logInfo.put("contentLength", httpRequest.getContentLength());

        logger.info(objectMapper.writeValueAsString(logInfo));
    }

    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }
}